//
// Created by Jisam on 06/09/2024 8:54 PM.
// Solution of  P1514 [NOIP2010 提高组] 引水入城
//#pragma GCC optimize(3)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <stack>

using namespace std;

// 定义dx和dy数组，用于表示八个方向的横纵坐标偏移量
int dx[] = {-1, 1, 0, 0, 1, 1, -1, -1,};
int dy[] = {0, 0, -1, 1, 1, -1, -1, 1,};

// 定义宏nx和ny，用于计算在某个方向上的相邻位置的坐标
#define nx x+dx[i]
#define ny y+dy[i]

// 定义常量maxn，用于表示地图的最大边长
const int maxn = 510;
// 定义l和r数组，用于存储每个位置的左边和右边的边界
int l[maxn][maxn],r[maxn][maxn];
// 定义high数组，用于存储每个位置的高度
int high[maxn][maxn];
// 定义n和m，分别表示地图的行数和列数
int n,m;
// 定义vis数组，用于标记每个位置是否被访问过
bool vis[maxn][maxn];
// 定义dfs函数，用于深度优先搜索
inline void dfs(int x,int y)
{
    // 将当前位置标记为已访问
    vis[x][y]=true;
    // 遍历四个方向
    for (int i=0;i<4;i++){
        // 如果相邻位置超出地图范围，则跳过
        if (nx<1 || nx>n || ny<1 || ny>m) continue;
        // 如果相邻位置的高度大于等于当前位置的高度，则跳过
        if (high[nx][ny]>=high[x][y]) continue;
        // 如果相邻位置未被访问过，则递归调用dfs函数
        if (!vis[nx][ny])dfs(nx,ny);
        // 更新当前位置的左边和右边的边界
        l[x][y]=min(l[x][y],l[nx][ny]);
        r[x][y]=max(r[x][y],r[nx][ny]);
    }
}

// 定义read函数，用于从输入中读取一个整数
inline int read()
{
    int x = 0,f = 1;
    char ch = getchar();
    while (ch < '0' || ch>'9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}

inline void write(int x)
{
    if (x < 0) putchar('-'), x = -x;
    if(x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
    return;
}

// 定义solution函数，用于解决具体的问题
void solution() {
    // 读取地图的行数和列数
//    cin >> n >> m;
    n = read();
    m = read();

    // 初始化vis数组和l、r数组
    memset(vis,false,sizeof vis);
    memset(l,0x3f,sizeof l);
    memset(r,0,sizeof r);
    // 初始化地图最后一行的左边和右边的边界
    for(int i = 1; i <= m ;  i ++)
    {
        l[n][i] = r[n][i]= i;
    }
    // 读取地图上每个位置的高度
    for(int i = 1 ; i <= n ; i ++)
    {
        for(int j = 1; j <= m ; j ++)
        {
            high[i][j] = read();
        }
    }
    // 从地图第一行的每个位置开始进行深度优先搜索
    for (int i=1;i<=m;i++)
        if (!vis[1][i]) dfs(1,i);
    // 判断是否存在从第一行到最后一行的路径
    bool flag = false;
    int cnt = 0;

    for(int i = 1 ;i <= m ; i ++)
    {
        if(!vis[n][i])
        {
            flag = true;
            cnt ++;
        }
    }
    // 如果存在从第一行到最后一行的路径，则输出0和路径的数量
    if(flag){
        puts("0");
//        printf("%d",cnt);
        write(cnt);
        return ;
    }
    // 定义left变量，用于表示当前搜索的左边界的最小值
    int left = 1;
    // 循环搜索从第一行到最后一行的路径
    while(left <= m)
    {
        int maxr = 0;
        // 遍历第一行的每个位置
        for(int i = 1; i <= m ; i ++)
        {
            // 如果当前位置的左边界小于等于left，则更新最右边界的最大值
            if(l[1][i] <= left)
            {
                maxr = max(maxr,r[1][i]);
            }
        }
        // 增加路径数量，更新left的值为最右边界的最大值加一
        cnt ++;
        left = maxr + 1;
    }
    // 输出1和路径的数量
    puts("1");
    write(cnt);
//    printf("%d",cnt);
}


int main() {
//    code_by_jisam;
    int T = 1;
//    cin >> T;
    while (T--) {
        solution();
    }
    return 0;
}